package com.zxcl.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zxcl.constant.BusinessEnum;
import com.zxcl.constant.MqConstant;
import com.zxcl.domain.*;
import com.zxcl.dto.OrderConfirmDTO;
import com.zxcl.dto.OrderSubmitDTO;
import com.zxcl.dto.PageDTO;
import com.zxcl.ex.BusinessException;
import com.zxcl.feign.OrderCartFeign;
import com.zxcl.feign.OrderMemberFeign;
import com.zxcl.feign.OrderProdFeign;
import com.zxcl.feign.OrderStoreFeign;
import com.zxcl.mapper.OrderItemMapper;
import com.zxcl.mapper.OrderMapper;
import com.zxcl.model.*;
import com.zxcl.money.CalculateAmount;
import com.zxcl.money.handler.*;
import com.zxcl.service.OrderItemService;
import com.zxcl.service.OrderService;
import com.zxcl.utils.AuthUtil;
import com.zxcl.vo.OrderConfirmVO;
import com.zxcl.vo.OrderStatusVO;
import com.zxcl.vo.OrderVO;
import lombok.extern.log4j.Log4j2;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


@Service
@Log4j2
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService, ApplicationContextAware {




    @Autowired
    private OrderMemberFeign orderMemberFeign;

    @Autowired
    private OrderProdFeign orderProdFeign;

    @Autowired
    private OrderStoreFeign orderStoreFeign;

    @Autowired
    private OrderCartFeign orderCartFeign;


    private CalculateAmount calculateAmount;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 查询订单状态数量
     *
     * @return
     */

    @Override
    public OrderStatusVO orderStatusCount() {
        OrderStatusVO orderStatusVO = new OrderStatusVO();
        String openId = AuthUtil.getOpenId();
        List<Order> orderList = getBaseMapper().selectList(new LambdaQueryWrapper<Order>()
                .select(Order::getStatus)
                .eq(Order::getOpenId, openId)
                .eq(Order::getDeleteStatus, 0)
        );
        if (!CollectionUtils.isEmpty(orderList)) {
            long unPay = orderList.stream().filter(order -> order.getStatus().equals(1)).count();
            long payed = orderList.stream().filter(order -> order.getStatus().equals(2)).count();
            long consignment = orderList.stream().filter(order -> order.getStatus().equals(3)).count();
            orderStatusVO.setConsignment(consignment);
            orderStatusVO.setPayed(payed);
            orderStatusVO.setUnPay(unPay);
        }
        return orderStatusVO;
    }


//        Integer AllStatus=0;
//        Integer noDeleteStatus=0;
//        String openId = AuthUtil.getOpenId();
//        Page<OrderDetailVO> page = new Page<>();
//        Page<Order> orderPage = new Page<>(pageDTO.getCurrent(), pageDTO.getSize());
//        Page<Order> orderPage1 = getBaseMapper().selectPage(orderPage, new LambdaQueryWrapper<Order>()
//                .eq(Order::getOpenId, openId)
//                .eq(!AllStatus.equals(status), Order::getStatus, status)
//                .eq(Order::getDeleteStatus, noDeleteStatus));
//        page.setTotal(orderPage1.getTotal());
//        page.setSize(orderPage1.getSize());
//        page.setCurrent(orderPage1.getCurrent());
//        List<Order> records = orderPage1.getRecords();
//        //创建一个接受商品详情表的集合
//        List<OrderDetailVO> orderItemsAll = new ArrayList<>();
//        for (Order record : records) {
//            OrderDetailVO orderDetailVO = new OrderDetailVO();
//            BeanUtils.copyProperties(record,orderDetailVO);
//            List<OrderItem> orderItems = orderItemService.getBaseMapper().selectList(new LambdaQueryWrapper<OrderItem>()
//                    .eq(OrderItem::getOrderNumber, record.getOrderNumber()));
//            orderDetailVO.setOrderItemDtos(orderItems);
//            orderItemsAll.add(orderDetailVO);
//        }
//        //放入分页数据中
//        page.setRecords(orderItemsAll);
//        return page;

    @Autowired
    private OrderItemService orderItemService;



    /**
     * 分页查询订单列表
     * @param pageDTO
     * @param status
     * @return
     */
    @Override
    public Page<OrderVO> loadOrderPage(PageDTO pageDTO, Integer status) {
        Page<OrderVO> pageVO = new Page<>(pageDTO.getCurrent(), pageDTO.getSize());

        Page<Order> page = new Page<>(pageDTO.getCurrent(), pageDTO.getSize());
        String openId = AuthUtil.getOpenId();

        List<OrderVO> orderItemsAll = new ArrayList<>();
        if (status == 0){
            Page<Order> orderPage = getBaseMapper().selectPage(page, new LambdaQueryWrapper<Order>()
                    .eq(Order::getOpenId, openId)
                    .eq(Order::getDeleteStatus, 0)
            );
            List<Order> records = orderPage.getRecords();

            for (Order record : records) {
                OrderVO orderDetailVO = new OrderVO();
                BeanUtils.copyProperties(record,orderDetailVO);
                List<OrderItem> orderItems = orderItemService.getBaseMapper().selectList(new LambdaQueryWrapper<OrderItem>()
                        .eq(OrderItem::getOrderNumber, record.getOrderNumber()));
                orderDetailVO.setOrderItemDtos(orderItems);
                orderItemsAll.add(orderDetailVO);
            }

            BeanUtils.copyProperties(orderPage,pageVO);
            pageVO.setRecords(orderItemsAll);
            return pageVO;
        }

        Page<Order> orderPage = getBaseMapper().selectPage(page, new LambdaQueryWrapper<Order>()
                .eq(Order::getOpenId, openId)
                .eq(Order::getDeleteStatus, 0)
                .eq(Order::getStatus,status)
        );
        List<Order> records = orderPage.getRecords();

        for (Order record : records) {
            OrderVO orderDetailVO = new OrderVO();
            BeanUtils.copyProperties(record,orderDetailVO);
            List<OrderItem> orderItems = orderItemService.getBaseMapper().selectList(new LambdaQueryWrapper<OrderItem>()
                    .eq(OrderItem::getOrderNumber, record.getOrderNumber()));
            orderDetailVO.setOrderItemDtos(orderItems);
            orderItemsAll.add(orderDetailVO);
        }

        BeanUtils.copyProperties(orderPage,pageVO);
        pageVO.setRecords(orderItemsAll);
        return pageVO;
    }

    /**
     * 订单确认
     * 单品确认
     *  shopDetail  OrderItem  sku  member_addr
     * @param orderConfirmDTO
     * @return
     */
    @Override  //OrderConfirmDTO 订单确认对象
    public OrderConfirmVO orderConfirm(OrderConfirmDTO orderConfirmDTO) {
        OrderConfirmVO orderConfirmVO = new OrderConfirmVO();

        //查询当前用户默认收获地址
        Result<MemberAddr> defaultAddrResult = orderMemberFeign.getDefaultAddr(AuthUtil.getOpenId());
        //没有考虑远程调用失败的问题，因为这里如果失败了，我也可以点进去设置它的收货地址  熔断自行处理
        MemberAddr memberAddr = defaultAddrResult.getData();
        orderConfirmVO.setMemberAddr(memberAddr);

        //创建一个计算费用的对象
        List<SkuBuyModel> skuBuyModels = new ArrayList<>();

        //判断是单品还是购物车入口
        List<Long> basketIds = orderConfirmDTO.getBasketIds();
        if (CollectionUtils.isEmpty(basketIds)){
            //单品调用的方法
            prod2Confirm(orderConfirmVO,orderConfirmDTO.getProdConfirmModel(),skuBuyModels); //skuBuyModels 商品购买模型
        }
        else {
            //购物车调用的方法
            cart2Confirm(orderConfirmVO, orderConfirmDTO.getBasketIds(), skuBuyModels);

        }

        // 计算总金额 责任链模式  商品金额 活动折扣 优惠券金额 运费金额  最终金额
        OrderMoneyContext context = new OrderMoneyContext();
        context.setSkuBuyModels(skuBuyModels);
        context.setOpenId(AuthUtil.getOpenId());
        //执行过程会赋值的
        calculateAmount.calculate(context);
        orderConfirmVO.setTransfee(context.getTransfee());
        orderConfirmVO.setActualTotal(context.getActualTotal());
        orderConfirmVO.setShopReduce(context.getShopReduce());
        orderConfirmVO.setTotalMoney(context.getTotalMoney());

        return orderConfirmVO;
    }

    /**
     * 下单 [会有分布式事务问题  seata去解决]
     * 1.生成订单号
     * 2.扣减库在[远程调用]
     * 3.清空购物车[远程调用]
     * 4.写订单
     * 5.写MQ的延时消息
     * 6.对接微信支付返回微信支付的payerid:
     *
     * @param orderSubmitDTO
     * @return
     */
    @Override
    public Map<String, String> orderSubmit(OrderSubmitDTO orderSubmitDTO) {
        String openId = AuthUtil.getOpenId();

        //1.创建订单号
        String orderSn = createOrderSn();
        //2.清空购物车
        clearBasket(orderSubmitDTO);
        //3.扣减库存
        changeStock(orderSubmitDTO);
        //4.写订单
        writeOrder(orderSubmitDTO,orderSn,openId);
        //5.发延时消息
//        writeMsQueue(orderSubmitDTO);
        //6.请求微信支付的凭证
        //wxPay();
        return null;
    }

    @Autowired
    private OrderItemMapper orderItemMapper;

    /**
     * 写订单 order orderItem (每一项都有自己的费用)
     * 费用需要重新计算 (客户端传入的金额不要使用，选的一些优惠修改)
     * @param orderSubmitDTO
     * @param orderSn
     * @param openId
     */
    private void writeOrder(OrderSubmitDTO orderSubmitDTO, String orderSn, String openId) {
        // skuIds  远程调用 skuList
        List<Long> skuIds = orderSubmitDTO.getShopOrders().stream().flatMap(shopOrder -> shopOrder.getShopOrderItems().stream())
                .map(OrderItem::getSkuId).collect(Collectors.toList());
        Result<List<Sku>> skuResult = orderProdFeign.getSkusByIds(skuIds);
        if (skuResult.getData().equals(BusinessEnum.OPERATION_FAIL.getCode())) {
            throw new BusinessException(skuResult.getMsg());
        }
        List<Sku> skuList = skuResult.getData();
        Map<Long, Sku> skuMap = skuList.stream().collect(Collectors.toMap(Sku::getSkuId, sku -> sku));
        ArrayList<SkuBuyModel> skuBuyModels = new ArrayList<>();
        //单品数量
        List<Integer> oneCounts = new ArrayList<>();
        // 写orderItem表
        orderSubmitDTO.getShopOrders().forEach(shopOrder -> {
            shopOrder.getShopOrderItems().forEach(orderItem -> {
                orderItem.setCreateTime(new Date());
                orderItem.setCommSts(0);
                orderItem.setOrderNumber(orderSn);
                // 金额数据
                Sku sku = skuMap.get(orderItem.getSkuId());
                BigDecimal price = sku.getPrice();
                Integer prodCount = orderItem.getProdCount();
                Long skuId = orderItem.getSkuId();
                orderItem.setPrice(sku.getPrice());
                // 计算单品总价
                BigDecimal oneMoney = price.multiply(new BigDecimal(prodCount.toString()));
                orderItem.setProductTotalAmount(oneMoney);
                // 写orderItem
                orderItemMapper.insert(orderItem);
                skuBuyModels.add(new SkuBuyModel(skuId, price, prodCount));
                oneCounts.add(prodCount);
            });
        });
        // （计算费用）
        OrderMoneyContext orderMoneyContext = new OrderMoneyContext();
        orderMoneyContext.setSkuBuyModels(skuBuyModels);
        orderMoneyContext.setOpenId(openId);
        calculateAmount.calculate(orderMoneyContext);
        // 写订单表
        Order order = new Order();
        order.setOpenId(openId);
        order.setOrderNumber(orderSn);
        order.setCreateTime(new Date());
        order.setUpdateTime(new Date());
        order.setRemarks(orderSubmitDTO.getRemarks());
        order.setIsPayed(false);
        order.setStatus(1);
        MemberAddr memberAddr = orderSubmitDTO.getMemberAddr();
        StringBuilder sb = new StringBuilder();
        String memberAddrDetails = sb.append(memberAddr.getProvince())
                .append(memberAddr.getCity())
                .append(memberAddr.getArea())
                .append(memberAddr.getAddr())
                .toString();
        order.setAddrOrderDetails(memberAddrDetails); // 收获地址
        Integer totalCount = oneCounts.stream().reduce(Integer::sum).get();
        order.setProductNums(totalCount);
        // 设置费用
        order.setActualTotal(orderMoneyContext.getActualTotal()); // 实付金额
        order.setFreightAmount(orderMoneyContext.getTransfee()); // 运费金额
        order.setReduceAmount(orderMoneyContext.getShopReduce()); // 折扣金额
        order.setTotalMoney(orderMoneyContext.getTotalMoney()); // 商品金额
        getBaseMapper().insert(order);
    }






    /**
     * 延时消息
     * @param orderSn
     * @param changeStock
     */
    private void writeMsQueue(String orderSn, ChangeStock changeStock) {
        //先写订单详情，因为有订单号就可以写订单详情了，尼玛的订单表和订单详情表不是都有订单好嘛？
        //订单详情写完了，费用已经算完了？ todo  购物车确认的时候不是都算过了嘛，为什么还有继续算呢？
        //前端传过来的价格有可能和后端不同？？  前端的数据都能改，  充值护院，免费充值会员
        Message<String> message = MessageBuilder.withPayload(JSON.toJSONString(changeStock))
                .setHeader(RocketMQHeaders.KEYS, orderSn)
                .build();
        // 1s 5s  10s 30s 1min 2min
        SendResult sendResult = rocketMQTemplate.syncSend(MqConstant.ORDER_MS_TOPIC, message, 6000, 5);
        log.info("发送订单延迟消息，订单号为:{},发送结果为:{}", orderSn, sendResult.getSendStatus());
    }

    /**
     * 改变库存
     *
     * @param orderSubmitDTO
     */
    private void changeStock(OrderSubmitDTO orderSubmitDTO) {
        List<SkuStock> skuStocks=new ArrayList<>();
        List<ProdStock> prodStocks=new ArrayList<>();
        //收集skuId count prodId  count
        orderSubmitDTO.getShopOrders().forEach(shopOrder -> {
            shopOrder.getShopOrderItems().forEach(orderItem -> {
                Long skuId = orderItem.getSkuId();
                Long prodId = orderItem.getProdId();
                String prodName = orderItem.getProdName();
                Integer prodCount = orderItem.getProdCount();
                SkuStock skuStock=new SkuStock();
                skuStock.setSkuId(skuId);
                skuStock.setCount(prodCount);
                skuStock.setProdName(prodName);
                skuStocks.add(skuStock);
                ///----合并处理    每一次循环,取出需要的prodId和 prodCount
                //orderItem中的prodId
                // 第一次进来 创建一个List<ProdStock>  prodStocks第一次是空的,filter是过滤出产品Id相同的,这样由于orderItem中的prodId可能相同,你每一次循环,我向里面收集的prodId我都是保证唯一的

                //因此第一次循环prodStockList为空,走下面这个, 第二次循环 的orderItem中的不同的
                List<ProdStock> prodStockList = prodStocks.stream().filter(prodStock -> prodStock.getProdId().equals(prodId))
                        .collect(Collectors.toList());
                if(CollectionUtils.isEmpty(prodStockList)){
                    ProdStock prodStock=new ProdStock();
                    prodStock.setProdId(prodId);
                    prodStock.setCount(prodCount);
                    prodStocks.add(prodStock);
                }else{
                    ProdStock prodStock = prodStockList.get(0); //收集它的
                    prodStock.setCount(prodStock.getCount()+prodCount);
                }
            });
        });
        //远程调用
        ChangeStock changeStock = new ChangeStock(skuStocks, prodStocks);
        Result<Boolean> result = this.orderProdFeign.changeStocks(changeStock);
        if (result.getCode().equals(BusinessEnum.OPERATION_FAIL.getCode())||!result.getData()) {
            //扣减库存失败
            throw new BusinessException(result.getMsg());
        }
    }



    /**
     * 购物车确认
     * @param orderConfirmVO
     * @param basketIds
     * @param skuBuyModels
     */
    private void cart2Confirm(OrderConfirmVO orderConfirmVO, List<Long> basketIds, List<SkuBuyModel> skuBuyModels) {

        //根据购物车的ids拿购物车数据
        Result<List<Basket>> basketsResult = this.orderCartFeign.getBasketsByIds(basketIds);
        if (basketsResult.getCode().equals(BusinessEnum.OPERATION_FAIL.getCode())) {
            throw new BusinessException(basketsResult.getMsg());
        }
        //取出购物车数据 既是basket每一行
        List<Basket> basketList = basketsResult.getData();
        //取出购物车里面的店铺IDS  每一行的list集合编程list里面装的id
        List<Long> shopIds = basketList.stream().map(Basket::getShopId).collect(Collectors.toList());
        //取出购物车里面的skuIds
        List<Long> skuIds = basketList.stream().map(Basket::getSkuId).collect(Collectors.toList());

        //根据shopIds拿店铺(多个)
        Result<List<ShopDetail>> shopDetailResult = this.orderStoreFeign.getShopDetailsByIds(shopIds);
        //处理调用异常的问题(自行处理熔断)
        if (shopDetailResult.getCode().equals(BusinessEnum.OPERATION_FAIL.getCode())) {
            throw new BusinessException(shopDetailResult.getMsg());
        }

        //取出店铺数据
        List<ShopDetail> shopDetails = shopDetailResult.getData();

        //拿sku  既是取出商品详情数据
        Result<List<Sku>> skusResult = this.orderProdFeign.getSkusByIds(skuIds);
        //处理调用异常的问题(自行处理熔断)
        if (skusResult.getCode().equals(BusinessEnum.OPERATION_FAIL.getCode())) {
            throw new BusinessException(skusResult.getMsg());
        }
        //取出List<Sku>
        List<Sku> skuList = skusResult.getData();

        //把shopDetails和skuList转成Map<Id,Obj>  这样可以根据主键id查找

        Map<Long, ShopDetail> shopDetailMap = shopDetails.stream().collect(Collectors.toMap(ShopDetail::getShopId, shopDetail -> shopDetail));
        Map<Long, Sku> skuMap = skuList.stream().collect(Collectors.toMap(Sku::getSkuId, sku -> sku));
        //组装数据
        //创建店铺的集合
        List<ShopOrder> shopOrders = new ArrayList<>();
        /** 购物车数据
         * skuId  shopId   count
         * 1        1       2
         * 2        1       4
         */

        basketList.forEach(basket -> {
            Long skuId = basket.getSkuId();
            Long shopId = basket.getShopId();
            Integer prodCount = basket.getProdCount();
            //根据shopId取出shop的数据
            ShopDetail shopDetail = shopDetailMap.get(shopId);
            //shopOrders 一开始是 new ArrayList<>(); 因此.filter里面也是空至于等于那也是空的呀
            List<ShopOrder> shopOrderList = shopOrders.stream()
                    .filter(shopOrder -> shopOrder.getShopId()
                            .equals(shopId)).collect(Collectors.toList()); //根据指定的条件
            if(CollectionUtils.isEmpty(shopOrderList)){
                //因为上面的缘故可以想到,shopOrderList一开始是空的, 因此他这个if里写的逻辑就是new 一个shopOrder组装好数据往shoporders中放
                ShopOrder shopOrder = new ShopOrder();
                shopOrder.setShopId(shopId);
                shopOrder.setShopLogo(shopDetail.getShopLogo());
                shopOrder.setShopName(shopDetail.getShopName());
                shopOrder.setShopLink(shopDetail.getShopAddress());
                //创建店铺的商品集合
                List<OrderItem> shopOrderItems = new ArrayList<>();
                //创建OrderItem
                OrderItem orderItem = new OrderItem();
                //从skuMap里面取出sku
                Sku sku = skuMap.get(skuId);
                BeanUtils.copyProperties(sku, orderItem);
                //设置数量
                orderItem.setProdCount(prodCount);
                //把orderItem添加到shopOrderItems
                shopOrderItems.add(orderItem);
                //把shopOrderItems交给shopOrder
                shopOrder.setShopOrderItems(shopOrderItems);
                //把shopOrder添加到shopOrders
                shopOrders.add(shopOrder);
                //组装算总金额数组
                skuBuyModels.add(new SkuBuyModel(skuId, sku.getPrice(), prodCount));
            }else{
                //可是由于这在循环中,所以第二次shopOrderList肯定不为空,因为shopOrders在第一次if中进行了add操作
                //那这一行就等于是在说取出第一个shopOrder, shopList里面装的是什么?
                ShopOrder shopOrder = shopOrderList.get(0);
                //创建店铺的商品集合
                List<OrderItem> shopOrderItems =shopOrder.getShopOrderItems();
                //创建OrderItem
                OrderItem orderItem = new OrderItem();
                //从skuMap里面取出sku
                Sku sku = skuMap.get(skuId);
                BeanUtils.copyProperties(sku, orderItem);
                //设置数量
                orderItem.setProdCount(prodCount);
                //把orderItem添加到shopOrderItems
                shopOrderItems.add(orderItem);
                //组装算总金额数组
                skuBuyModels.add(new SkuBuyModel(skuId, sku.getPrice(), prodCount));

            }
        });
        //放到orderConfirmVO
        orderConfirmVO.setShopOrders(shopOrders);

    }

    /**
     * 单品确认
     * 店铺信息和商品信息
     * @param orderConfirmVO
     * @param prodConfirmModel
     * @param skuBuyModels
     */
    private void prod2Confirm(OrderConfirmVO orderConfirmVO, ProdConfirmModel prodConfirmModel, List<SkuBuyModel> skuBuyModels) {
        //先拿到店铺id和商品id，当然这肯定是前端传过来的
        Long shopId = prodConfirmModel.getShopId();
        Long skuId = prodConfirmModel.getSkuId();
        //商品数量
        Integer prodCount = prodConfirmModel.getProdCount();

        //拿店铺
        Result<List<ShopDetail>> shopResult = orderStoreFeign.getShopDetailsByIds(Arrays.asList(shopId));
        //创建一个实现类去实现feign接口，加一个fall back，然后引入sentinel依赖
        if (shopResult.getCode().equals(BusinessEnum.OPERATION_FAIL.getCode())){
            throw new BusinessException(shopResult.getMsg());
        }
        ShopDetail shopDetail = shopResult.getData().get(0);

        //拿商品
        Result<List<Sku>> skuResult = orderProdFeign.getSkusByIds(Arrays.asList(skuId));
        if (skuResult.getCode().equals(BusinessEnum.OPERATION_FAIL.getCode())){
            throw new BusinessException(skuResult.getMsg());
        }
        //取出sku
        Sku sku = skuResult.getData().get(0);

        //创建店铺集合
        ArrayList<ShopOrder> shopOrders = new ArrayList<>();
        //创建店铺对象，new一个就行因为单品只有一个店铺

        List<OrderItem> shopOrderItems = new ArrayList<>();
        //问题是这里面的shopOrderItems是空的
        //所以创建具体的OrderItem
        OrderItem orderItem = new OrderItem();
        BeanUtils.copyProperties(prodConfirmModel,orderItem);
        BeanUtils.copyProperties(sku,orderItem);


        ShopOrder shopOrder = new ShopOrder(shopId, shopDetail.getShopName(), shopDetail.getShopLogo(), shopDetail.getShopAddress(), shopOrderItems);

        //因为就一个嘛，直接添加
        shopOrders.add(shopOrder);

        orderConfirmVO.setShopOrders(shopOrders);

        //组装算总金额
        skuBuyModels.add(new SkuBuyModel(skuId,sku.getPrice(),prodCount));

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

//        Map<String, CalculateAmount> moneyHandler = applicationContext.getBeansOfType(CalculateAmount.class);
//
//        CalculateAmount prodMoneyHandler = moneyHandler.get("prodMoneyHandler");
//        CalculateAmount actualMoneyHandler = moneyHandler.get("actualMoneyHandler");
//        CalculateAmount couponMoneyHandler = moneyHandler.get("couponMoneyHandler");
//        CalculateAmount reduceMoneyHandler = moneyHandler.get("reduceMoneyHandler");
//        CalculateAmount transMoneyHandler = moneyHandler.get("transMoneyHandler");

        //等于还是把存在ioc容器中的对象通过这里的ApplicationContextAware 取出来
        ProdMoneyHandler prodMoneyHandler = applicationContext.getBean(ProdMoneyHandler.class);
        ReduceMoneyHandler reduceMoneyHandler = applicationContext.getBean(ReduceMoneyHandler.class);
        CouponMoneyHandler couponMoneyHandler = applicationContext.getBean(CouponMoneyHandler.class);
        TransMoneyHandler transMoneyHandler = applicationContext.getBean(TransMoneyHandler.class);
        ActualMoneyHandler actualMoneyHandler = applicationContext.getBean(ActualMoneyHandler.class);

        // 排序
        prodMoneyHandler.setNextHandler(reduceMoneyHandler);
        reduceMoneyHandler.setNextHandler(couponMoneyHandler);
        couponMoneyHandler.setNextHandler(transMoneyHandler);
        transMoneyHandler.setNextHandler(actualMoneyHandler);
        this.calculateAmount = prodMoneyHandler;
    }

    @Autowired
    private Snowflake snowflake;

    /**
     * 分布式唯一id
     * 要求：
     * 唯一
     * 单调递增 （b-tree  b+-tree）
     * 建议携带时间戳
     * 不建议连续
     * --------------------------
     * 前置+时间戳+随机数  order_时间戳(yyyyMMddHHmmssSSS)+3位随机数
     * UUID 不建议
     * -------------------------
     * 雪花算法？ long(8字节64位)
     * 0(符号位) 41(时间戳) 5(机房id) 5(机器id) 12(序列号)
     * 世界上没有两片雪花是一模一样的
     * 美团leaf
     * 滴滴打车tinyId
     * 百度 uidGenerator
     *
     * @return
     */
    private String createOrderSn() {
        return snowflake.nextIdStr();
    }


    /**
     * 清空购物车
     * @param orderSubmitDTO
     */
    private void clearBasket(OrderSubmitDTO orderSubmitDTO) {
        if(orderSubmitDTO.getOrderEntry().equals(1L)){
            //单品下单，没有购物车
            return;
        }
//        List<Long> skuIds=new ArrayList<>();
//        orderSubmitDTO.getShopOrders().forEach(shopOrder -> {
//            shopOrder.getShopOrderItems().forEach(orderItem -> {
//                Long skuId = orderItem.getSkuId();
//                skuIds.add(skuId);
//            });
//        });
        //flatMap 是一个中间操作，用于将一个流中的每个元素映射为一个流，然后将这些流扁平化为单个流。
        //
        //具体而言，flatMap 接受一个函数作为参数，该函数将每个流中的元素映射为一个流。然后，flatMap 将这些流合并为一个单独的流，以便进行后续的操作。
        List<Long> skuIds = orderSubmitDTO.getShopOrders().stream().flatMap(shopOrder -> shopOrder.getShopOrderItems().stream())
                .map(OrderItem::getSkuId).collect(Collectors.toList());
        String openId = AuthUtil.getOpenId();
        if (orderSubmitDTO.getOrderEntry().equals("0")) {
            // 远程调用 清空购物车
            Result<Boolean> result = orderCartFeign.clearCart(skuIds, openId);
            if (result.getCode().equals(BusinessEnum.OPERATION_FAIL.getCode()) || !result.getData()) {
                // 清空失败
                throw new BusinessException(result.getMsg());
            }
        }
    }



}
